# @Time : 2024-11-02 9:27
# @Author : Fioman 
# @Phone : 13149920693
"""
在多线程的编程中,很容易遇到竞争条件,为了避免多个线程同时修改共享资源,我们可以使用锁机制.
比如Lock
"""
import threading
import time

# region 1. 使用锁的多线程操作全局变量
counter = 0
counterLock = threading.Lock()


def worker():
    for _ in range(100000):
        global counter
        counter += 1


def worker_with_lock():
    for _ in range(100000):
        global counter
        with counterLock:
            counter += 1


# 创建多个线程
threads = [threading.Thread(target=worker_with_lock) for _ in range(20)]
print(threads)
for thread in threads:
    thread.start()

for thread in threads:
    thread.join()
print("Counter Value: ", counter)

# endregion


# region 2. threading.RLock(可重入锁)
lock2 = threading.RLock()  # 如果是可重入锁,就是允许一个线程多次调用acquire()获取锁对象


# 而如果是普通的锁对象,下面的代码会阻塞在第二个lock2.acquire()这里,直到第一个lock2.acquire()释放


def worker2():
    print("获取锁...")
    lock2.acquire()
    print("第二次获取锁")
    lock2.acquire()  # 程序会卡在这里,等待第一个锁的释放
    print("第三次获取锁")
    lock2.acquire()
    lock2.release()


thread2 = threading.Thread(target=worker2)
thread2.start()
thread2.join()

# endregion


# region 4. Semaphore 信号量  允许设定同时访问某个资源的线程数量.它允许多个线程同时访问共享资源
semaphore = threading.Semaphore(2)  # 允许最多两个线程同时访问


def worker3(ident):
    print(f"Thread {ident} is waiting to access the resource")
    with semaphore:
        print(f"Thread {ident} has accessed the resource")
        time.sleep(2)
    print(f"thread {ident} has released the resource")


threads = [threading.Thread(target=worker3, args=(i,)) for i in range(10)]
for thread in threads:
    thread.start()

for thread in threads:
    thread.join()
# endregion

# region 5. threading.Condition  等待唤醒线程
# Condition 对象允许线程在某些条件下等待和唤醒,可以用于更复杂的线程同步机制.比如生产者和消费者模型
condition = threading.Condition()
sharedData = []


def producer():
    global sharedData
    for i in range(5):
        time.sleep(1)
        with condition:
            sharedData.append(i)
            print(f"Produced {i}")
            condition.notify()  # 唤醒一个等待的线程


def consumer():
    global sharedData
    for _ in range(5):
        with condition:
            condition.wait()
            item = sharedData.pop(0)
            print(f"Consumed {item}")


prodThread = threading.Thread(target=producer)
consThread = threading.Thread(target=consumer)
prodThread.start()
consThread.start()
prodThread.join()
consThread.join()

# endregion
